#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <sw/redis++/redis++.h>
#include <chrono>
#include <thread>

#include "util.hpp"

using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::unordered_map;
using std::vector;

using sw::redis::Redis;
using sw::redis::StringView;

using namespace std::chrono_literals;

// lpush 操作是头插
void Lpush(Redis& redis) {
    redis.flushdb();

    // 插入一个元素
    redis.lpush("key", "1");

    // 插入多个元素, 这里需要基于 列表初始化 initializer
    redis.lpush("key", {"2", "3", "4", "5"});

    // 插入多个元素, 基于容器的迭代器
    vector<string> inputs = {"5", "6", "7"};
    redis.lpush("key", inputs.begin(), inputs.end());

    vector<sw::redis::OptionalString> outputs;
    auto it = back_inserter(outputs);
    redis.lrange("key", 0, -1, it);

    PrintOp(outputs);
}


void Rpush(Redis& redis) {
    redis.flushdb();

    redis.rpush("key", "1");

    redis.rpush("key", {"2", "3", "4", "5"});

    vector<string> values = {"5", "6", "7"};

    redis.rpush("key", values.begin(), values.end());
}

void Pop(Redis& redis) {
    redis.flushdb();

    redis.rpush("key", {"1", "2", "3", "4", "5"});

    auto result = redis.lpop("key");
    if (result) {
        cout << "被 lpop 的元素 = " << result.value() << endl;
    }

    result = redis.rpop("key");
    if (result) {
        cout << "被 rpop 的元素 = " << result.value() << endl;
    }
}

void Blpop(Redis& redis) {
    redis.flushdb();

    redis.rpush("key", {"1", "2", "3", "4", "5"});

    // 返回值是 OptionalStringPair, (brpop 可以同时监听多个 key)
    // 拥有如下特征
    //    1. 该对象是 optional
    //    2. 里面包裹了一个 pair
    //    3. pair 里面是 string
    // 该函数会返回两个信息：1. 该元素属于哪个 list，当前被删除的元素
    // blpop 可以设定超时时间, 如果指定时间没有获取结果，那么就会返回一个无效值
    auto result = redis.brpop("key");

    if (result)
        cout << "key = " << result.value().first << " | value = " << result.value().second << endl;
}

int main()
{
    Redis redis("tcp://127.0.0.1:6379");

    Lpush(redis);

    // Rpush(redis);

    Pop(redis);

    Blpop(redis);
    
    return 0;
}